package com.hy.frame.util

import android.os.Build
import android.os.StatFs
import android.text.TextUtils
import android.webkit.MimeTypeMap
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.text.DecimalFormat

/**
 * 文件工具
 * 1. 获取文件或文件夹大小
 * 2. 删除文件或文件夹
 * + 必须先获取权限
 */
object FileUtil {
    const val SIZETYPE_B = 1// 获取文件大小单位为B的double值
    const val SIZETYPE_KB = 2// 获取文件大小单位为KB的double值
    const val SIZETYPE_MB = 3// 获取文件大小单位为MB的double值
    const val SIZETYPE_GB = 4// 获取文件大小单位为GB的double值

    /**
     * 获取文件指定文件或文件夹的大小
     * @param filePath 文件路径
     * @param sizeType 获取大小的类型SIZETYPE_B为B、SIZETYPE_KB为KB、SIZETYPE_MB为MB、SIZETYPE_GB为GB
     * @return Double
     */
    fun getFileOrFilesSize(filePath: String, sizeType: Int): Double {
        val file = File(filePath)
        var blockSize: Long = 0
        try {
            blockSize = if (file.isDirectory) {
                getFileSizes(file)
            } else {
                getFileSize(file)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            MyLog.e("getFileOrFilesSize", "获取失败!")
        }
        return formatFileSize(blockSize, sizeType)
    }

    /**
     * 获取文件指定文件或文件夹的大小 自动类型
     * @param filePath 文件路径
     * @return String 计算好的带B、KB、MB、GB的字符串
     */
    fun getFileOrFilesSizeStr(filePath: String): String {
        val file = File(filePath)
        var blockSize: Long = 0
        try {
            blockSize = if (file.isDirectory) {
                getFileSizes(file)
            } else {
                getFileSize(file)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            MyLog.e("getFileOrFilesSizeStr", "获取失败!")
        }
        return formatFileSizeStr(blockSize)
    }

    /**
     * 获取指定文件大小
     * @param file File
     * @return Long 单文件大小
     * @throws Exception
     */
    @Throws(Exception::class)
    private fun getFileSize(file: File): Long {
        var size: Long = 0
        if (file.exists()) {
            val fis: FileInputStream?
            fis = FileInputStream(file)
            size = fis.available().toLong()
            fis.close()
        } else {
            //file.createNewFile()
            MyLog.e("getFileSize", "文件不存在!")
        }
        return size
    }

    /**
     * 获取指定文件夹
     * @param file File
     * @return Long 单文件夹大小
     * @throws Exception
     */
    @Throws(Exception::class)
    private fun getFileSizes(file: File): Long {
        var size: Long = 0
        val files = file.listFiles()
        for (i in files.indices) {
            size += if (files[i].isDirectory) {
                getFileSizes(files[i])
            } else {
                getFileSize(files[i])
            }
        }
        return size
    }

    /**
     * 转换文件大小
     * @param size Long 文件的大小(B)
     * @return String 计算好的带B、KB、MB、GB的字符串
     */
    fun formatFileSizeStr(size: Long): String {
        val df = DecimalFormat("#.00")
        val fileSizeString: String?
        val wrongSize = "0B"
        if (size == 0L) {
            return wrongSize
        }
        if (size < 1024) {
            fileSizeString = df.format(size.toDouble()) + "B"
        } else if (size < 1048576) {
            fileSizeString = df.format(size.toDouble() / 1024) + "KB"
        } else if (size < 1073741824) {
            fileSizeString = df.format(size.toDouble() / 1048576) + "MB"
        } else {
            fileSizeString = df.format(size.toDouble() / 1073741824) + "GB"
        }
        return fileSizeString
    }

    /**
     * 转换文件大小,指定转换的类型
     * @param size
     * @param sizeType
     * @return
     */
    fun formatFileSize(size: Long, sizeType: Int): Double {
        val df = DecimalFormat("#.00")
        return when (sizeType) {
            SIZETYPE_B -> df.format(size.toDouble()).toDouble()
            SIZETYPE_KB -> df.format(size.toDouble() / 1024).toDouble()
            SIZETYPE_MB -> df.format(size.toDouble() / 1048576).toDouble()
            SIZETYPE_GB -> df.format(size.toDouble() / 1073741824).toDouble()
            else -> 0.0
        }
    }

    /**
     * 删除该路径下的所有文件，不包含当前路径 耗时操作
     * @param path
     * @return 是否成功
     */
    fun delAllFile(path: String?): Boolean {
        if (path == null)
            return false
        val file = File(path)
        if (!file.exists() || !file.isDirectory)
            return false
        try {
            val tempList = file.listFiles()
            for (item in tempList) {
                if (item.isDirectory) {
                    delFolder(item.absolutePath)//先删除文件夹里面的文件
                } else
                    item.delete()
            }
        } catch (e: Exception) {
            MyLog.e("delAllFile", "文件不存在!")
        }
        return true
    }

    private fun delFolder(folderPath: String): Boolean {
        val file = File(folderPath)
        if (!file.exists() || !file.isDirectory)
            return false
        try {
            val tempList = file.listFiles()
            for (item in tempList) {
                if (item.isDirectory) {
                    delFolder(item.absolutePath)//先删除文件夹里面的文件
                }
                item.delete()//再删除空文件夹
            }
        } catch (e: Exception) {
            MyLog.e("delFolder", "文件不存在!")
        }
        return true
    }

    /**
     * Access to a directory available size.
     * @param path path.
     * @return Long size.
     */
    fun getDirSize(path: String): Long {
        val stat = StatFs(path)
        val blockSize: Long
        val availableBlocks: Long
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            blockSize = stat.blockSizeLong
            availableBlocks = stat.availableBlocksLong
        } else {
            blockSize = stat.blockSize.toLong()
            availableBlocks = stat.availableBlocks.toLong()
        }
        return availableBlocks * blockSize
    }

    /**
     * If the folder can be written.
     * @param path path.
     * @return True: success, or false: failure.
     */
    fun canWrite(path: String): Boolean {
        return File(path).canWrite()
    }

    /**
     * If the folder can be read.
     * @param path path.
     * @return True: success, or false: failure.
     */
    fun canRead(path: String): Boolean {
        return File(path).canRead()
    }

    /**
     * Create a folder, If the folder exists is not created.
     * @param folderPath folder path.
     * @return True: success, or false: failure.
     */
    fun createFolder(folderPath: String): Boolean {
        if (!TextUtils.isEmpty(folderPath)) {
            val folder = File(folderPath)
            return createFolder(folder)
        }
        return false
    }

    /**
     * Create a folder, If the folder exists is not created.
     * @param targetFolder folder path.
     * @return True: success, or false: failure.
     */
    fun createFolder(targetFolder: File): Boolean {
        if (targetFolder.exists())
            return true
        return targetFolder.mkdirs()
    }

    /**
     * Create a file, If the file exists is not created.
     * @param filePath file path.
     * @return True: success, or false: failure.
     */
    fun createFile(filePath: String): Boolean {
        if (!TextUtils.isEmpty(filePath)) {
            val file = File(filePath)
            return createFile(file)
        }
        return false
    }

    /**
     * Create a file, If the file exists is not created.
     * @param targetFile file.
     * @return True: success, or false: failure.
     */
    fun createFile(targetFile: File): Boolean {
        if (targetFile.exists())
            return true
        try {
            return targetFile.createNewFile()
        } catch (e: IOException) {
            return false
        }

    }

    /**
     * Create a new file, if the file exists, delete and create again.
     * @param filePath file path.
     * @return True: success, or false: failure.
     */
    fun createNewFile(filePath: String): Boolean {
        if (!TextUtils.isEmpty(filePath)) {
            val file = File(filePath)
            return createNewFile(file)
        }
        return false
    }

    /**
     * Create a new file, if the file exists, delete and create again.
     * @param targetFile file.
     * @return True: success, or false: failure.
     */
    fun createNewFile(targetFile: File): Boolean {
        if (targetFile.exists())
            targetFile.delete()
        try {
            return targetFile.createNewFile()
        } catch (e: IOException) {
            return false
        }

    }

    /**
     * Return the MIME type for the given url.
     * @param url the url, path…
     * @return The MIME type for the given extension or null iff there is none.
     */
    fun getMimeTypeByUrl(url: String): String? {
        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url))
    }

}